export const formatDate = (iDate, sFormat = 'yyyy-MM-dd HH:mm:ss', defSymbol = '') => {
  if (!iDate) {
    return defSymbol
  }
  const dDate = new Date(iDate)
  const year = dDate.getFullYear() // 年
  let month = dDate.getMonth() + 1 // 月
  if (month < 10) {
    month = '0' + month
  }
  let date = dDate.getDate() // 日
  if (date < 10) {
    date = '0' + date
  }
  let hour = dDate.getHours() // 时
  if (hour < 10) {
    hour = '0' + hour
  }
  let minute = dDate.getMinutes() // 分
  if (minute < 10) {
    minute = '0' + minute
  }
  let second = dDate.getSeconds() // 秒
  if (second < 10) {
    second = '0' + second
  }
  const millisecond = dDate.getMilliseconds() // 毫秒
  if (sFormat.indexOf('yyyy') >= 0) {
    sFormat = sFormat.replace('yyyy', year + '')
  }
  if (sFormat.indexOf('MM') >= 0) {
    sFormat = sFormat.replace('MM', month + '')
  }
  if (sFormat.indexOf('dd') >= 0) {
    sFormat = sFormat.replace('dd', date + '')
  }
  if (sFormat.indexOf('HH') >= 0) {
    sFormat = sFormat.replace('HH', hour + '')
  }
  if (sFormat.indexOf('mm') >= 0) {
    sFormat = sFormat.replace('mm', minute + '')
  }
  if (sFormat.indexOf('ss') >= 0) {
    sFormat = sFormat.replace('ss', second + '')
  }
  if (sFormat.indexOf('SSS') >= 0) {
    sFormat = sFormat.replace('SSS', millisecond + '')
  }
  return sFormat
}

/**
 * @description: 根据自身 value 值 与 arr 中 code 比对展示对应的 Name 名称
 * @param {*} val 自身的值
 * @param {*} arr 数组
 * @param {*} code 需要比对的键
 * @param {*} name 需要返回的name
 * @param {*} defSymbol 默认符
 * @return {*} 返回所需的值
 */
export const accCodeToName = (val, arr, code = 'value', name = 'name', defSymbol = '--') => {
  if (val === undefined || val === null || val === '') return defSymbol
  if (!Array.isArray(arr)) return defSymbol
  const _data = arr.find(v => v[code] === val)
  return (_data && _data[name]) ? _data[name] : defSymbol
}

export const debounce = (func, wait = 16, immediate = false) => {
  let timeout, args, context, timestamp, result;
  const later = function () {
    const last = +new Date() - timestamp;
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };
  return function () {
    let context = this;
    args = arguments;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }
    return result;
  };
};

/* 工具类 */
/*
 * 随机数，10位时间戳 连接4位随机整数 e.g. 1428910956 + "" +3482
 * */
export const random14 = () => {
  return (
    Math.round(new Date().getTime() / 1000) +
    '' +
    Math.floor(Math.random() * 9000 + 1000)
  )
}

/*
   * 科学计数
   * */
export const toThousands = num => {
  if (isNaN(num)) {
    return ''
  }
  let pre = ''
  if (num < 0) {
    pre = '-'
  }
  num = Math.abs(num).toString()
  let result = ''
  while (num.length > 3) {
    result = ',' + num.slice(-3) + result
    num = num.slice(0, num.length - 3)
  }
  if (num) {
    result = pre + num + result
  }
  return result
}

export const degreeStandard = (cormax, cormin, cornumber) => {
  // var tmpmax
  // var tmpmin
  var corstep
  var tmpstep
  var tmpnumber
  var temp
  var extranumber
  if (cormax <= cormin) {
    return
  }
  corstep = (cormax - cormin) / cornumber
  if (Math.pow(10, parseInt(Math.log(corstep) / Math.log(10))) === corstep) {
    temp = Math.pow(10, parseInt(Math.log(corstep) / Math.log(10)))
  } else {
    temp = Math.pow(10, parseInt(Math.log(corstep) / Math.log(10)) + 1)
  }
  tmpstep = (corstep / temp).toFixed(6)
  // 选取规范步长
  if (tmpstep >= 0 && tmpstep <= 0.1) {
    tmpstep = 0.1
  } else if (tmpstep >= 0.100001 && tmpstep <= 0.2) {
    tmpstep = 0.2
  } else if (tmpstep >= 0.200001 && tmpstep <= 0.25) {
    tmpstep = 0.25
  } else if (tmpstep >= 0.250001 && tmpstep <= 0.5) {
    tmpstep = 0.5
  } else {
    tmpstep = 1
  }
  tmpstep = tmpstep * temp
  if (parseInt(cormin / tmpstep) !== cormin / tmpstep) {
    if (cormin < 0) {
      cormin = -1 * Math.ceil(Math.abs(cormin / tmpstep)) * tmpstep
    } else {
      cormin = parseInt(Math.abs(cormin / tmpstep)) * tmpstep
    }
  }
  if (parseInt(cormax / tmpstep) !== cormax / tmpstep) {
    cormax = parseInt(cormax / tmpstep + 1) * tmpstep
  }
  tmpnumber = (cormax - cormin) / tmpstep
  if (tmpnumber < cornumber) {
    extranumber = cornumber - tmpnumber
    tmpnumber = cornumber
    if (extranumber % 2 === 0) {
      cormax = cormax + tmpstep * parseInt(extranumber / 2)
    } else {
      cormax = cormax + tmpstep * parseInt(extranumber / 2 + 1)
    }
    cormin = cormin - tmpstep * parseInt(extranumber / 2)
  }
  cornumber = tmpnumber
  return [cormax, cormin, cornumber]
}

/**
 * @summary 根据key从对象数组中拿对象
 * @param {array} list 对象数组
 * @param {string} key
 * @param {string} keyName
 * @return {Object} 返回对象 / NULL
 * @example
 */
export const getObjFromArrayByKey = (list, key, keyName) => {
  let _o = null
  if (!list || list.length <= 0) {
    return _o
  }
  for (let i = 0; i < list.length; i++) {
    if (key === list[i][keyName]) {
      _o = list[i]
      break
    }
  }
  return _o
}

/**
 * @summary 根据key从对象数组中拿对象
 * @param {array} list 对象数组
 * @param {string} key
 * @param {string} keyName
 * @param {string} keyName
 * @return {Number|String|Boolean} 返回值 / NULL
 * @example
 */
export const getValFromArrayByKey = (list, key, keyName, valName) => {
  if (!list || list.length <= 0) {
    return null
  }
  let _val = null
  for (let i = 0; i < list.length; i++) {
    if (key === list[i][keyName]) {
      _val = list[i][valName]
      break
    }
  }
  return _val
}

/**
 * @summary 该方法用于将有父子关系的数组转换成树形结构的数组
 * @param {Array} data 具有父子关系的数组
 * @param {Object} dataMode 数据模型 dataMode: { id: 'id', pid: 'pid', children: 'children'}
 * @param {Int | String} rootId 根节点ID
 * @return {Array} 树形结构的数组
 */
export const translateDataToTree = (data, dataMode, rootId) => {
  // 没有父节点的数据
  const parents = data.filter(
    value => !value[dataMode.pid] || value[dataMode.pid] === rootId
  )
  // console.log('parents', parents)
  // 有父节点的数据
  const children = data.filter(
    value =>
      value[dataMode.pid] !== undefined &&
      value[dataMode.pid] != null &&
      value[dataMode.pid] !== rootId
  )
  // 定义转换方法的具体实现
  const translator = (parents, children) => {
    // 遍历父节点数据
    parents.forEach(parent => {
      // 遍历子节点数据
      children.forEach((current, index) => {
        // 此时找到父节点对应的一个子节点
        if (current[dataMode.pid] === parent[dataMode.id]) {
          // 对子节点数据进行深复制，这里只支持部分类型的数据深复制，对深复制不了解的童靴可以先去了解下深复制
          const temp = JSON.parse(JSON.stringify(children))
          // 让当前子节点从temp中移除，temp作为新的子节点数据，这里是为了让递归时，子节点的遍历次数更少，如果父子关系的层级越多，越有利
          temp.splice(index, 1)
          // 让当前子节点作为唯一的父节点，去递归查找其对应的子节点
          translator([current], temp)
          // 把找到子节点放入父节点的children属性中
          typeof parent.children !== 'undefined'
            ? parent.children.push(current)
            : (parent.children = [current])
        }
      })
    })
  }
  // 调用转换方法
  translator(parents, children)
  // 返回最终的结果
  return parents
}

// 截取的字符串
export const substringEllipsis = (str, len, flow = '...') => {
  if (!str) return ''
  str = str.toString()
  var newStr = ''
  var reg = /[\u4e00-\u9fa5]/g
  var strLength = str.replace(reg, '**').length

  if (strLength <= len + (strLength % 2 === 0 ? 2 : 1)) return str

  for (var i = 0, newLength = 0, singleChar; i < strLength; i++) {
    singleChar = str.charAt(i).toString()
    if (singleChar.match(reg) != null) {
      newLength += 2
    } else {
      newLength++
    }
    if (newLength > len) {
      break
    }
    newStr += singleChar
  }

  if (strLength > len) {
    newStr = newStr + flow
  }
  return newStr
}

// EPSG:3857转换经纬度(EPSG:4326)
export const mercatorTolonlat = mercator => {
  var lonlat = {
    x: 0,
    y: 0
  }
  var x = (mercator.x / 20037508.34) * 180
  var y = (mercator.y / 20037508.34) * 180
  y =
    (180 / Math.PI) *
    (2 * Math.atan(Math.exp((y * Math.PI) / 180)) - Math.PI / 2)
  lonlat.x = x
  lonlat.y = y
  return lonlat
}
// 经纬度(EPSG:4326)转换EPSG:3857
export const lonLat2Mercator = lonlat => {
  var mercator = {
    x: 0,
    y: 0
  }
  var earthRad = 6378137.0
  mercator.x = ((lonlat.lng * Math.PI) / 180) * earthRad
  var a = (lonlat.lat * Math.PI) / 180
  mercator.y =
    (earthRad / 2) * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)))
  return mercator
}

// 传入 hex 颜色 和透明度 转变成 rgba 格式
export const hexToRgba = (hex, opacity) => {
  let rgbaColor = ''
  const reg = /^#[\da-f]{6}$/i
  if (reg.test(hex)) {
    rgbaColor = `rgba(${parseInt('0x' + hex.slice(1, 3))},${parseInt(
      '0x' + hex.slice(3, 5)
    )},${parseInt('0x' + hex.slice(5, 7))},${opacity})`
  }
  return rgbaColor
}

// 千分位展示
export const formatMoney = num => {
  return (num + '').replace(/(\d{1,3})(?=(\d{3})+(?:$|\.))/g, '$1,')
}


export const getD = (sDate, endDate) => {
  var sDate = new Date(sDate);
  var eDate = new Date(endDate);

  if (eDate.getFullYear() - sDate.getFullYear() > 1) {//先比较年
    return true;
  } else if (eDate.getMonth() - sDate.getMonth() > 1) {//再比较月
    return true;
  } else if (eDate.getMonth() - sDate.getMonth() == 1) {
    if (eDate.getDate() - sDate.getDate() >= 1) {
      return true;
    }
  }
  else if (eDate.getFullYear() - sDate.getFullYear() == 1) {
    if (eDate.getMonth()+12 - sDate.getMonth() > 1) {
      return true;
    }
    else if (eDate.getDate() - sDate.getDate() >= 1) {
      return true;
    }
  }
  return false;
}

/*
JSON对象 深度合并
// 示例1
const obj1 = { x: { y: 1 }, z: [3, 4] }
const obj2 = { x: { z: 3 }, y: 2 }
console.log(deepMerge(obj1, obj2)) // 输出 { x: { y: 1, z: 3 }, y: 2, z: [3, 4] }

// 示例2
const obj3 = { x: { y: { z: 1 } }, w: [2] }
const obj4 = { x: { y: { w: 3 } }, z: 3 }
console.log(deepMerge(obj3, obj4)) // 输出 { x: { y: { z: 1, w: 3 } }, w: [2], z: 3 }
*/
export function deepMerge(target, source) {
  // 遍历源JSON对象
  for (const key of Object.keys(source)) {
    // 如果源对象当前属性是一个JSON对象，则递归地对其进行合并
    if (source[key] instanceof Object) {
      Object.assign(source[key], deepMerge(target[key], source[key]))
    }
  }
  // 合并所有属性
  return Object.assign({}, target, source)
}

/**
 * @param {string} path
 * @returns {Boolean}
 */
export function isExternal(path) {
  const isExternal = /^(https?:|http?:|mailto:|tel:)/.test(path);
  return isExternal;
}
